Skip to content

Add permanent invitations and export medication changes as well#315

Open
pauljohanneskraft wants to merge 4 commits into
mainfrom
june-2026-changes
Open

Add permanent invitations and export medication changes as well#315
pauljohanneskraft wants to merge 4 commits into
mainfrom
june-2026-changes

Conversation

@pauljohanneskraft

@pauljohanneskraft pauljohanneskraft commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Add permanent invitations and export medication changes as well

♻️ Current situation & Problem

Invitation codes may also be made permanent as to allow to not create an invitation for each patient explicitly. Also, the patient data export should also contain medication changes.

⚙️ Release Notes

  • Allow invitations to be set permanently
  • Add medication changes to patient data export

📚 Documentation

Please ensure that you properly document any additions in conformance to Spezi Documentation Guide.
You can use this section to describe your solution, but we encourage contributors to document your reasoning and changes using in-line documentation.

✅ Testing

  • Adapted testing accordingly

Code of Conduct & Contributing Guidelines

By creating and submitting this pull request, you agree to follow our Code of Conduct and Contributing Guidelines:

Summary by CodeRabbit

  • New Features

    • Added support for permanent invitations that can be reused by multiple distinct users, with automatic cleanup of non-permanent invitations after enrollment.
    • Enhanced medication request exports to include comprehensive lifecycle tracking with creation, update, and removal date columns.
  • Bug Fixes

    • Improved null-safety for invitation code processing.
  • Chores

    • Updated .gitignore for local environment configuration files.

Copilot AI review requested due to automatic review settings June 7, 2026 18:22
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds permanent invitations that can be reused across multiple users with seeded data retention, implements conditional invitation cleanup during enrollment based on permanence, and retrofits medication-request exports to reconstruct lifecycle dates (created, last-updated, removed) from Firestore history tracking rather than relying solely on live documents.

Changes

Permanent Reusable Invitations

Layer / File(s) Summary
Invitation permanent property
functions/models/src/types/invitation.ts, functions/models/src/functions/createInvitation.ts
Invitation type declares a readonly permanent: boolean property defaulting to false; Zod schema and converter serialize/deserialize this field; createInvitation input schema imports and uses optionalish to accept optional permanent boolean input.
Create invitation implementation and tests
functions/src/functions/createInvitation.ts, functions/src/functions/createInvitation.test.ts
createInvitation function uses optional chaining for null-safe auth?.email access; tests verify non-permanent invitations default to false and permanent invitations (with or without auth) are stored with permanent === true.
Enrollment cleanup for permanent invitations
functions/src/services/user/databaseUserService.ts, functions/src/functions/enrollUser.test.ts
finishUserEnrollment reads the permanent flag and conditionally deletes invitation documents and seeded sub-collection items only for non-permanent invitations. Test helpers and integration tests verify permanent invitations survive reuse by multiple users while non-permanent invitations are deleted after first enrollment.

Medication History Export

Layer / File(s) Summary
Lifecycle history reconstruction helper
functions/src/services/export/defaultExportService.ts
New generic LifecycleRecord interface encapsulates reconstructed content plus optional created, lastUpdated, removed timestamps. New lifecycleRecords helper queries /history collection by document path prefix, groups and sorts history entries, determines lifecycle timestamps, merges live content or latest historical snapshot, and appends live documents not in history.
Medication export with history reconstruction
functions/src/services/export/defaultExportService.ts
addUserMedicationRequests now calls lifecycleRecords helper instead of using only live medication-request documents. CSV schema expands with created, lastUpdated, removed columns populated from lifecycle timestamps.
Export history integration tests
functions/src/functions/exportData.test.ts
Integration test constructs three medication scenarios (added then removed, dosage changed, live-only), exports data, and validates CSV header, row collapsing, and correct population of lifecycle columns for each scenario.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and clearly summarizes the two main changes: permanent invitations and medication changes export, matching the core objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch june-2026-changes

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for reusable (permanent) invitation codes and extends the patient data export to include medication lifecycle information derived from the global /history collection.

Changes:

  • Add a permanent flag to invitations and adjust enrollment finalization to keep permanent invitations (and their seeded subcollections) for reuse.
  • Enhance medication export to reconstruct lifecycle records (created/updated/removed) by merging live documents with /history.
  • Update/extend emulator tests and fixtures to cover permanent invitation reuse and medication lifecycle export.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
functions/src/tests/resources/patientExport.zip Updates the expected export fixture (Git LFS pointer change).
functions/src/services/user/databaseUserService.ts Keeps invitation docs/subcollections when invitation.permanent is set.
functions/src/services/export/defaultExportService.ts Adds lifecycle reconstruction for medication requests and exports created/updated/removed timestamps.
functions/src/functions/exportData.test.ts Adds test coverage for medication lifecycle reconstruction in export.
functions/src/functions/enrollUser.test.ts Adds tests ensuring permanent invitations are reusable and non-permanent invitations are deleted.
functions/src/functions/createInvitation.test.ts Adds assertions/tests for permanent defaulting to false and being set to true when requested.
functions/models/src/types/invitation.ts Extends Invitation model + converter to include permanent with a default of false.
functions/models/src/functions/createInvitation.ts Extends create-invitation input schema to accept optional permanent.
.gitignore Ignores *.local.* files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread functions/src/services/export/defaultExportService.ts
Comment thread functions/src/services/export/defaultExportService.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.gitignore (1)

5-5: .gitignore *.local.* is broad—confirm intent/scope

  • There are currently no files in this repo matching *.local.* (nor *.local.js/json/ts), so this mainly affects future files.
  • Current “local” occurrences are in localization-related filenames (e.g., ...+localization.ts, localizedText.ts) and don’t match the ".local." pattern anyway.
  • Please confirm that “local” here is meant for local environment/config overrides; if so, consider narrowing the rule to the specific extensions you want (and/or add a brief comment).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.gitignore at line 5, The .gitignore entry "*.local.*" is overly broad and
may accidentally ignore localization files; replace it with a narrowed pattern
(e.g., target specific config/file extensions like "*.local.env", "*.local.json"
or "*.local.js") and add a brief comment above the rule explaining it's for
local environment/config overrides; update the rule where shown ("*.local.*") to
the chosen specific patterns so localization-related filenames (e.g., files
containing "localization" or "localizedText") are not inadvertently excluded.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@functions/src/services/export/defaultExportService.ts`:
- Around line 353-356: The code currently sets created = entries.at(0)?.date
which can mistakenly treat the first tracked history row as creation; change
this so created is only populated when that history row is explicitly an
insertion: inspect the earliest nonNullEntries element for an insertion flag
(e.g. entry.operation === 'insert' or entry.isInsert === true) and only then set
created to that entry.date; otherwise leave created undefined/null and continue
to use lastUpdated = nonNullEntries.at(-1)?.date; update the logic around
nonNullEntries and created to reflect this conditional check.

---

Nitpick comments:
In @.gitignore:
- Line 5: The .gitignore entry "*.local.*" is overly broad and may accidentally
ignore localization files; replace it with a narrowed pattern (e.g., target
specific config/file extensions like "*.local.env", "*.local.json" or
"*.local.js") and add a brief comment above the rule explaining it's for local
environment/config overrides; update the rule where shown ("*.local.*") to the
chosen specific patterns so localization-related filenames (e.g., files
containing "localization" or "localizedText") are not inadvertently excluded.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 22af8df3-e9b8-4048-bd05-849850356268

📥 Commits

Reviewing files that changed from the base of the PR and between 411de15 and 0627e5f.

⛔ Files ignored due to path filters (1)
  • functions/src/tests/resources/patientExport.zip is excluded by !**/*.zip
📒 Files selected for processing (8)
  • .gitignore
  • functions/models/src/functions/createInvitation.ts
  • functions/models/src/types/invitation.ts
  • functions/src/functions/createInvitation.test.ts
  • functions/src/functions/enrollUser.test.ts
  • functions/src/functions/exportData.test.ts
  • functions/src/services/export/defaultExportService.ts
  • functions/src/services/user/databaseUserService.ts

Comment thread functions/src/services/export/defaultExportService.ts
pauljohanneskraft and others added 2 commits June 7, 2026 20:28
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.90%. Comparing base (411de15) to head (13c9e60).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #315      +/-   ##
==========================================
+ Coverage   82.77%   82.90%   +0.14%     
==========================================
  Files          93       93              
  Lines        3836     3877      +41     
  Branches      976      987      +11     
==========================================
+ Hits         3175     3214      +39     
- Misses        654      656       +2     
  Partials        7        7              
Files with missing lines Coverage Δ
functions/src/functions/createInvitation.ts 80.65% <100.00%> (ø)
...ctions/src/services/export/defaultExportService.ts 90.44% <100.00%> (+1.90%) ⬆️
functions/src/services/user/databaseUserService.ts 82.28% <100.00%> (+0.35%) ⬆️

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 411de15...13c9e60. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-and-test.yml:
- Around line 21-26: The reuseaction job lacks explicit least-privilege
permissions and currently relies on default GITHUB_TOKEN permissions which may
be broader than necessary. Add a permissions block to the reuseaction job
specifying only the minimum required permissions needed for REUSE compliance
checking, following the same principle as the buildandtest job permissions
defined on line 83.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 62050013-f750-4adc-840a-ff682eff4754

📥 Commits

Reviewing files that changed from the base of the PR and between 0627e5f and cf550fe.

📒 Files selected for processing (5)
  • .github/workflows/build-and-test.yml
  • functions/models/src/functions/createInvitation.ts
  • functions/src/functions/createInvitation.test.ts
  • functions/src/functions/createInvitation.ts
  • functions/src/services/export/defaultExportService.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • functions/src/functions/createInvitation.test.ts
  • functions/models/src/functions/createInvitation.ts
  • functions/src/services/export/defaultExportService.ts

Comment on lines 21 to +26
reuseaction:
name: REUSE Compliance Check
uses: StanfordBDHG/.github/.github/workflows/reuse.yml@v2
markdownlinkcheck:
name: Markdown Link Check
uses: StanfordBDHG/.github/.github/workflows/markdown-link-check.yml@v2.3
# markdownlinkcheck:
# name: Markdown Link Check
# uses: StanfordBDHG/.github/.github/workflows/markdown-link-check.yml@v2.3

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Set explicit least-privilege permissions for reuseaction.

Line 83 permissions only scope buildandtest; reuseaction currently falls back to default GITHUB_TOKEN permissions, which can be broader than needed.

Suggested fix
   reuseaction:
     name: REUSE Compliance Check
+    permissions:
+      contents: read
     uses: StanfordBDHG/.github/.github/workflows/reuse.yml@v2
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reuseaction:
name: REUSE Compliance Check
uses: StanfordBDHG/.github/.github/workflows/reuse.yml@v2
markdownlinkcheck:
name: Markdown Link Check
uses: StanfordBDHG/.github/.github/workflows/markdown-link-check.yml@v2.3
# markdownlinkcheck:
# name: Markdown Link Check
# uses: StanfordBDHG/.github/.github/workflows/markdown-link-check.yml@v2.3
reuseaction:
name: REUSE Compliance Check
permissions:
contents: read
uses: StanfordBDHG/.github/.github/workflows/reuse.yml@v2
# markdownlinkcheck:
# name: Markdown Link Check
# uses: StanfordBDHG/.github/.github/workflows/markdown-link-check.yml@v2.3
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 21-26: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)


[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-and-test.yml around lines 21 - 26, The reuseaction
job lacks explicit least-privilege permissions and currently relies on default
GITHUB_TOKEN permissions which may be broader than necessary. Add a permissions
block to the reuseaction job specifying only the minimum required permissions
needed for REUSE compliance checking, following the same principle as the
buildandtest job permissions defined on line 83.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants